package game;

import javax.microedition.khronos.opengles.GL10;

import gfx.Camera;
import gfx.Glyphs;
import gfx.Image;
import gfx.PressableButton;
import gfx.Spritesheet;
import util.GameClock;
import util.GameVars;
import util.InteractableInterface;
import util.Logger;
import util.VertexBuffer;

import android.graphics.PointF;

public class Menu {
	private PressableButton currentButton;
	private PressableButton buttonUp;
	private PressableButton buttonRight;
	private PressableButton buttonDown;
	private PressableButton buttonLeft;
	private int currentButtonNum;
	
	private float[] controlBoxVertexes = new float[12];
	// I didn't like this implementation.  Commented out.
//	private short[] selectedStageArray;

	private short buttonArrayIterator;
	private short touchIterator;
	private short nextGameLayer = GameVars.GAME_LAYER_MENU;
	
	private short currentLayer = GameVars.MENU_LAYER_MENU;
	private short nextLayer = -1;

	private short stageSelection;
	private short tempSelectedStage;
	private short levelSelection;
	private short tempSelectedLevel;
	private short difficultySelection;
	private short selectedDifficulty;
	
	private boolean isLoaded = false;
	private boolean inMenu = true;
	private boolean close = false;
	
	private PressableButton[] buttonArray;
	private PressableButton[] arrowArray;
	private PressableButton nextButton;
	private PressableButton backButton;	
	private PressableButton playButton;
	
	StageSelect ss;
	DifficultySelect ds;
	LevelSelect ls;
	
	public Menu(){
		isLoaded = false;
	}
	
	public void loadMenu(short character, short world, short stage){
		load();

		ss = new StageSelect();
		
		tempSelectedStage = stage;
		
		currentLayer = GameVars.MENU_LAYER_STAGE_SELECT;
	}
	
	public void load(){		
		nextButton = new PressableButton(GameVars.BUTTON_TYPE_MENU, "Next", null, 3, .75f, GameVars.BUTTON_NUM_NEXT);
		backButton = new PressableButton(GameVars.BUTTON_TYPE_MENU, "Back", null, 3, .75f, GameVars.BUTTON_NUM_BACK);
		playButton = new PressableButton(GameVars.BUTTON_TYPE_MENU, "Play", null, 3, .75f, GameVars.BUTTON_NUM_PLAY);

		buttonUp = new PressableButton(GameVars.BUTTON_TYPE_ARROW_UP, "Up", null, 3, .75f, GameVars.BUTTON_NUM_UP);
		buttonRight = new PressableButton(GameVars.BUTTON_TYPE_ARROW_RIGHT, "Right", null, 1, 2f, GameVars.BUTTON_NUM_RIGHT);
		buttonDown = new PressableButton(GameVars.BUTTON_TYPE_ARROW_DOWN, "Down", null, 3, .75f, GameVars.BUTTON_NUM_DOWN);
		buttonLeft = new PressableButton(GameVars.BUTTON_TYPE_ARROW_LEFT, "Left", null, 1, 2f, GameVars.BUTTON_NUM_LEFT);
		
		nextButton.setCenter(3, .5f);
		backButton.setCenter(1.5f,9.5f);
		playButton.setCenter(3, .5f);
		
		buttonRight.setCenter(5.5f, 6.5f);
		buttonLeft.setCenter(0.5f, 6.5f);
		buttonUp.setCenter(3f, 8.5f);
		buttonDown.setCenter(3f, 3.5f);
		buttonUp.setWidth(2);
		buttonUp.setHeight(1);
		buttonDown.setWidth(2);
		buttonDown.setHeight(1);
		
		arrowArray = new PressableButton[4];
		arrowArray[0] = buttonUp;
		arrowArray[1] = buttonRight;
		arrowArray[2] = buttonDown;
		arrowArray[3] = buttonLeft;

		buttonArray = new PressableButton[5];
		buttonArray[0] = new PressableButton(GameVars.BUTTON_TYPE_MENU, "Play", null, 3, .75f, GameVars.BUTTON_NUM_PLAY);
		buttonArray[1] = new PressableButton(GameVars.BUTTON_TYPE_MENU, "High Score", null, 3, .75f, GameVars.BUTTON_NUM_HIGH_SCORES);
		buttonArray[2] = new PressableButton(GameVars.BUTTON_TYPE_MENU, "Options", null, 3, .75f, GameVars.BUTTON_NUM_OPTION);
		buttonArray[3] = new PressableButton(GameVars.BUTTON_TYPE_MENU, "Extras", null, 3, .75f, GameVars.BUTTON_NUM_EXTRAS);
		buttonArray[4] = new PressableButton(GameVars.BUTTON_TYPE_MENU, "Quit", null, 3, .75f, GameVars.BUTTON_NUM_QUIT);
		
		for(buttonArrayIterator = 0; buttonArrayIterator < buttonArray.length; ++buttonArrayIterator)
			buttonArray[buttonArrayIterator].setCenter(2.5f + buttonArrayIterator%2, 8.5f - buttonArrayIterator - buttonArrayIterator * .25f);
		
		isLoaded = true;
		
		difficultySelection = -1;
	}
	
	public void draw(GL10 gl){
		switch(currentLayer){
		case GameVars.MENU_LAYER_MENU:
				for(buttonArrayIterator = 0; buttonArrayIterator < buttonArray.length; ++buttonArrayIterator){
					buttonArray[buttonArrayIterator].draw(gl);
				}
			break;
		case GameVars.MENU_LAYER_STAGE_SELECT:
			if(ss.isLoaded())
				ss.draw(gl);
			break;
		case GameVars.MENU_LAYER_LEVEL_SELECT:
			if(ls.isLoaded())
				ls.draw(gl);
			break;
		case GameVars.MENU_LAYER_DIFFICULTY_SELECT:
			if(ds.isLoaded())
				ds.draw(gl);
			break;
		}
	}
	
	private void drawControlBox(GL10 gl){
		// Standard Box Draw.
		// TODO Change 3 to a variable somewhere.
		// TODO Addendum: There's a 3 down in Handle Touch of Stage (to avoid touch stuff).
		controlBoxVertexes[0] = 0;
		controlBoxVertexes[1] = 0;
		controlBoxVertexes[2] = 0;
		controlBoxVertexes[3] = 0;
		controlBoxVertexes[4] = 3;
		controlBoxVertexes[5] = 0;
		controlBoxVertexes[6] = Camera.GL_WIDTH;
		controlBoxVertexes[7] = 0;
		controlBoxVertexes[8] = 0;
		controlBoxVertexes[9] = Camera.GL_WIDTH;
		controlBoxVertexes[10] = 3;
		controlBoxVertexes[11] = 0;
		
		gl.glPushMatrix();
		gl.glDisable(GL10.GL_TEXTURE_2D);
		gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
		gl.glFrontFace(GL10.GL_CW);
		gl.glVertexPointer(3, GL10.GL_FLOAT, 0, VertexBuffer.getVertexBuffer(controlBoxVertexes));
		// TODO Change to a changeable setting.

		gl.glColor4f(0, 0, 0, 1);
		gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, controlBoxVertexes.length / 3);
		
		gl.glColor4f(1, 1, 1, 1);
		gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
		gl.glEnable(GL10.GL_TEXTURE_2D);
		gl.glPopMatrix();		
	}
	
	// TODO Depending on the memory load, investigate changing these to boolean of show instead, and keeping them loaded until stage launch.
	public void update(long time){
		if(nextLayer != -1){
			currentLayer = nextLayer;
			nextLayer = -1;
		}
		switch(currentLayer){
		case GameVars.MENU_LAYER_STAGE_SELECT:
			if(ss == null)
				ss = new StageSelect();
			ss.update(time);
			break;
		case GameVars.MENU_LAYER_LEVEL_SELECT:
			if(ls == null)
				ls = new LevelSelect();
			ls.update(time);
			break;
		case GameVars.MENU_LAYER_MENU:
			break;
		case GameVars.MENU_LAYER_DIFFICULTY_SELECT:
			if(ds == null)
				ds = new DifficultySelect();
			ds.update(time);
			break;
		}
	}

	public boolean isLoaded(){ return isLoaded; }
	public boolean inMenu(){ return inMenu; }
	public void toggleMenu(){ inMenu = !inMenu; }
	public short getNextGameLayer(){ return nextGameLayer; }
	public short getStageSelection(){ return (short) (stageSelection * GameVars.LEVEL_START_INDEX[stageSelection] + levelSelection); }
	public short getDifficultySelection(){ return difficultySelection; }
	public boolean close(){ return close; }
	
	public void buttonHandler(){
		switch(currentButtonNum){
		case GameVars.BUTTON_NUM_PLAY:
			if(currentLayer == GameVars.MENU_LAYER_MENU){
				nextLayer = GameVars.MENU_LAYER_STAGE_SELECT;
			}
			else{ nextGameLayer = GameVars.GAME_LAYER_STAGE; inMenu = false;}
			break;
		case GameVars.BUTTON_NUM_BACK:
			nextLayer = (short) (currentLayer - 1);
			break;
		case GameVars.BUTTON_NUM_NEXT:
//			Logger.log("Next Pressed");
			nextLayer = (short) (currentLayer + 1);
			break;
		case GameVars.BUTTON_NUM_HIGH_SCORES:
			break;
		case GameVars.BUTTON_NUM_OPTION:
			break;
		case GameVars.BUTTON_NUM_EXTRAS:
			break;
		case GameVars.BUTTON_NUM_QUIT:
			close = true;
			break;
		case GameVars.BUTTON_NUM_RIGHT:
			if(currentLayer == GameVars.MENU_LAYER_STAGE_SELECT){
				tempSelectedStage = (short) (stageSelection < GameVars.STAGE_COUNT - 1 ? ++stageSelection : stageSelection);
			}
			else if(currentLayer == GameVars.MENU_LAYER_LEVEL_SELECT){
				tempSelectedLevel = (short) (levelSelection < GameVars.LEVEL_COUNT[stageSelection] - 1 ? ++levelSelection : levelSelection);
			}
			break;
		case GameVars.BUTTON_NUM_LEFT:
			if(currentLayer == GameVars.MENU_LAYER_STAGE_SELECT){
				tempSelectedStage = (short) (stageSelection > 0 ? --stageSelection : stageSelection);
			}
			else if(currentLayer == GameVars.MENU_LAYER_LEVEL_SELECT){
				tempSelectedLevel = (short) (levelSelection > 0 ? --levelSelection : levelSelection);
			}
			break;
		case GameVars.BUTTON_NUM_UP:
			break;
		case GameVars.BUTTON_NUM_DOWN:
			break;
		}
	}
	
	public void handleTouch(PointF loc){
		switch(currentLayer){
		case GameVars.MENU_LAYER_MENU:
			for(touchIterator = 0; touchIterator < buttonArray.length; ++touchIterator)
				if(buttonArray[touchIterator].isPressed(loc))
					currentButton = buttonArray[touchIterator];
			break;
		case GameVars.MENU_LAYER_STAGE_SELECT:
			if(ss.handleTouch(loc)) return;
			
			for(touchIterator = 0; touchIterator < arrowArray.length; ++touchIterator)
				if(arrowArray[touchIterator].isPressed(loc)){
					currentButton = arrowArray[touchIterator];
					return;
				}
			
			if(backButton.isPressed(loc)){ currentButton = backButton; return; }
			if(nextButton.isPressed(loc)){ currentButton = nextButton; return; }
			// Moving to Difficulty Selection
//			if(playButton.isPressed(loc)) if(stageSelection >= 0){ currentButton = playButton; return; }
			break;
		case GameVars.MENU_LAYER_LEVEL_SELECT:
			if(ls.handleTouch(loc)) return;
			
			for(touchIterator = 0; touchIterator < arrowArray.length; ++touchIterator)
				if(arrowArray[touchIterator].isPressed(loc)){
					currentButton = arrowArray[touchIterator];
					return;
				}
			
			if(backButton.isPressed(loc)){ currentButton = backButton; return; }
			if(nextButton.isPressed(loc)){ currentButton = nextButton; return; }
			// Moving to Difficulty Selection
//			if(playButton.isPressed(loc)) if(stageSelection >= 0){ currentButton = playButton; return; }
			break;
		case GameVars.MENU_LAYER_DIFFICULTY_SELECT:
			if(ds.handleTouch(loc)) return;
			
			if(backButton.isPressed(loc)){ currentButton = backButton; return; }
			if(playButton.isPressed(loc)) if(difficultySelection >= 0){ currentButton = playButton; return; }
		}
		
	}

	// Used primarily for scrolling through selections (Characters, stages, worlds).
	public void handleDrag(PointF location) {
		
	}

	public boolean handleUp(PointF location) {
		if(currentButton != null)
			if(currentButton.isPressed(location)){
				currentButtonNum = currentButton.getNum();
				currentButton = null;
				buttonHandler();
				return true;
			}
		currentButton = null;
		if(currentLayer == GameVars.MENU_LAYER_STAGE_SELECT && ss != null){
			return ss.handleUp(location);
		}
		if(currentLayer == GameVars.MENU_LAYER_LEVEL_SELECT && ls != null){
			return ls.handleUp(location);
		}
		if(currentLayer == GameVars.MENU_LAYER_DIFFICULTY_SELECT && ds != null){
			return ds.handleUp(location);
		}
		return false;
	}
	
	public boolean handleBackPress(){
		if(currentLayer == GameVars.MENU_LAYER_MENU){
			return true;
		}
		nextLayer = (short) (currentLayer - 1);
		return false;
	}
		
	public class StageSelect{
		private boolean isLoaded = false;
		
		public StageSelect(){
			stageSelection = 0;
			
			tempSelectedStage = 0;
			
			isLoaded = true;
		}
		
		public void update(long time){

			if(stageSelection != tempSelectedStage)
				stageSelection = tempSelectedStage;
		}
		
		public void draw(GL10 gl){			
			backButton.draw(gl);
			
			drawControlBox(gl);
			
			nextButton.draw(gl);

			if(stageSelection == GameVars.STAGE_COUNT - 1)
				gl.glColor4f(1, 1, 1, 0.25f);
			buttonRight.draw(gl);
			if(stageSelection == 0)
				gl.glColor4f(1, 1, 1, 0.25f);
			buttonLeft.draw(gl);
			
			// Text Stuffs
			// Control Box 
			//	Stage
			gl.glPushMatrix();
			gl.glTranslatef(3f, 2.75f, 0);
//				gl.glColor4f(1, 1, 1, 1);
			Glyphs.drawString(gl, "Stage: " + stageSelection, null, GameVars.TEXT_ALIGNMENT_CENTER);
			gl.glPopMatrix();
		}
		
		public boolean handleTouch(PointF loc){
			if(loc.y < 3) return false;
			
			return false;
		}

		// Used primarily for scrolling through selections (Characters, stages, worlds).
		public void handleDrag(PointF location) {
			
		}

		public boolean handleUp(PointF location) {
			return false;
		}
		
		public boolean isLoaded(){ return isLoaded; }
	}

	
	public class LevelSelect{
		private boolean isLoaded = false;
		
		public LevelSelect(){
			levelSelection = 0;
			
			tempSelectedLevel = 0;
			
			isLoaded = true;
		}
		
		public void update(long time){

			if(levelSelection != tempSelectedLevel)
				levelSelection = tempSelectedLevel;
		}
		
		public void draw(GL10 gl){			
			backButton.draw(gl);
			
			drawControlBox(gl);
			
			nextButton.draw(gl);

			if(levelSelection == GameVars.LEVEL_COUNT[stageSelection] - 1)
				gl.glColor4f(1, 1, 1, 0.25f);
			buttonRight.draw(gl);
			if(levelSelection == 0)
				gl.glColor4f(1, 1, 1, 0.25f);
			buttonLeft.draw(gl);
			
			// Text Stuffs
			// Control Box 
			//	Stage
			gl.glPushMatrix();
			gl.glTranslatef(3f, 2.75f, 0);
//				gl.glColor4f(1, 1, 1, 1);
			Glyphs.drawMultiLinedString(gl, "Stage: " + GameVars.LEVEL_STRINGS[stageSelection][levelSelection], null, GameVars.TEXT_ALIGNMENT_CENTER, 5);
			gl.glPopMatrix();
		}
		
		public boolean handleTouch(PointF loc){
			if(loc.y < 3) return false;
			
			return false;
		}

		// Used primarily for scrolling through selections (Characters, stages, worlds).
		public void handleDrag(PointF location) {
			
		}

		public boolean handleUp(PointF location) {
			return false;
		}
		
		public boolean isLoaded(){ return isLoaded; }
	}
	
	// TODO Implement
	public class DifficultySelect{
		private short difficultyIterator;
		private short drawIterator;
		
		private boolean isLoaded = false;
		
		private PressableButton[] difficultyButtonArray;
		
		public DifficultySelect(){
			selectedDifficulty = -1;
			difficultyButtonArray = new PressableButton[GameVars.BUTTON_NUM_DIFFICULTIES.length];
			
			for(short i = 0; i < difficultyButtonArray.length; ++i)
				difficultyButtonArray[i] = new PressableButton(GameVars.BUTTON_TYPE_MENU, GameVars.DIFFICULTY_STRINGS[i], null, 3, .75f, GameVars.BUTTON_NUM_DIFFICULTIES[i]);

			for(short di = 0; di < difficultyButtonArray.length; ++di)
				difficultyButtonArray[di].setCenter(2.5f + di%2, 8.5f - di - di * .25f);
			
			isLoaded = true;
		}
		
		public void update(long time){
			
		}
		
		public void draw(GL10 gl){
			for(drawIterator = 0; drawIterator < difficultyButtonArray.length; ++drawIterator){
				gl.glPushMatrix();
				if(drawIterator != difficultySelection)
					gl.glColor4f(1f, 1f, 1f, .25f);
				difficultyButtonArray[drawIterator].draw(gl);
				gl.glPopMatrix();
			}
			
			drawControlBox(gl);
			
			backButton.draw(gl);
			
			if(difficultySelection == -1)
				gl.glColor4f(1, 1, 1, 0.25f);
			playButton.draw(gl);
		}
		
		public boolean handleTouch(PointF loc){
			for(difficultyIterator = 0; difficultyIterator < GameVars.BUTTON_NUM_DIFFICULTIES.length; ++difficultyIterator)
				if(difficultyButtonArray[difficultyIterator].isPressed(loc)){
					selectedDifficulty = difficultyIterator;
					return true;
				}
			return false;
		}

		// Used primarily for scrolling through selections (Characters, stages, worlds).
		public void handleDrag(PointF location) {
			
		}

		public boolean handleUp(PointF location) {
			if(selectedDifficulty >= 0)
				if(difficultyButtonArray[selectedDifficulty].isPressed(location)){
					difficultySelection = selectedDifficulty;
					return true;
				}
			return false;
		}
		
		public boolean isLoaded(){ return isLoaded; }
		public short getSelectedDifficulty(){ return difficultySelection; }
	}
}
